﻿using Microsoft.AspNetCore.Mvc;
using System.Linq.Expressions;
using System.Text.Json.Serialization;

namespace Seagull.Foundation
{
    /// <summary>
    /// 表示
    /// <typeparamref name="TEntity"/>
    /// 对象的实体字典（序列化时会排除实体字段以外的键值对象）。
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    [JsonConverter(typeof(Seagull.Internal.EntityDictionaryJsonConverterFactory))]
    public class EntityDictionary<TEntity> : IEntityDictionary<TEntity> where TEntity : class
    {
        private readonly Dictionary<string, object?> _entities = new();

        /// <summary>
        /// 获取包含在 Seagull.Foundation.EntityDictionary`1
        /// 中的键/值对的数目。
        /// </summary>
        public int Count => this._entities.Count;

        /// <summary>
        /// 是否包含指定的键。
        /// </summary>
        /// <typeparam name="TProp"></typeparam>
        /// <param name="property"></param>
        /// <returns></returns>
        public bool ContainsKey<TProp>(Expression<Func<TEntity, TProp>> property)
        {
            string propertyName = GetPropertyName(property);
            return this._entities.ContainsKey(propertyName);
        }

        string GetPropertyName<TProp>(Expression<Func<TEntity, TProp>> propertyExpression)
        {
            if (propertyExpression.Body is MemberExpression memberSelectorExpression)
            {
                var property = memberSelectorExpression.Member as PropertyInfo;
                if (property != null)
                {
                    return property.Name;
                }
            }
            throw new ArgumentException("property must be a member expression.");
        }

        /// <summary>
        /// 获取对象的属性。
        /// </summary>
        /// <typeparam name="TProp"></typeparam>
        /// <param name="property"></param>
        /// <returns></returns>
        public TProp Item<TProp>(Expression<Func<TEntity, TProp>> property)
        {
            return this.Value(property);
        }

        /// <summary>
        /// 替换对象的属性。
        /// </summary>
        /// <typeparam name="TProp"></typeparam>
        /// <param name="property"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public EntityDictionary<TEntity> Item<TProp>(Expression<Func<TEntity, TProp>> property, TProp value)
        {
            string propertyName = GetPropertyName(property);
            return this.Replace(propertyName, value);
        }

        /// <summary>
        /// 替换对象的属性。
        /// </summary>
        /// <typeparam name="TProp"></typeparam>
        /// <param name="property"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public EntityDictionary<TEntity> Replace<TProp>(Expression<Func<TEntity, TProp>> property, TProp value)
        {
            string propertyName = GetPropertyName(property);
            return this.Replace(propertyName, value);
        }

        /// <summary>
        /// 替换对象的属性。
        /// </summary>
        /// <typeparam name="TProp"></typeparam>
        /// <param name="propertyName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public EntityDictionary<TEntity> Replace<TProp>(string propertyName, TProp value)
        {
            _entities[propertyName] = value;
            return this;
        }

        /// <summary>
        /// 移除对象的属性。
        /// </summary>
        /// <typeparam name="TProp"></typeparam>
        /// <param name="property"></param>
        /// <returns></returns>
        public EntityDictionary<TEntity> Remove<TProp>(Expression<Func<TEntity, TProp>> property)
        {
            string propertyName = GetPropertyName(property);
            _entities[propertyName] = null;
            return this;
        }

        /// <summary>
        /// 获取对象的属性。
        /// </summary>
        /// <typeparam name="TProp"></typeparam>
        /// <param name="property"></param>
        /// <returns></returns>
        public TProp Value<TProp>(Expression<Func<TEntity, TProp>> property)
        {
            string propertyName = GetPropertyName(property);
            return (TProp)_entities[propertyName];
        }

        /// <summary>
        /// 获取对象的属性。
        /// </summary>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public object Value(string propertyName)
        {
            return _entities[propertyName];
        }

        /// <summary>
        /// 将EntityDictionary`
        /// <typeparamref name="TEntity"/>
        /// `转换为实例对象。
        /// </summary>
        /// <returns></returns>
        public TEntity Instance()
        {
            object instance;
            if (App.HttpContext is not null)
            {
                instance = App.HttpContext.RequestServices.GetService<TEntity>();
            }
            else
            {
                instance = App._provider.GetService<TEntity>();
            }
            if (instance is null)
            {
                var ctor = typeof(TEntity).GetConstructor(Array.Empty<Type>());
                if (ctor is not null)
                    instance = ctor.Invoke(null);
                else
                    throw new NullReferenceException($"没有找到 {typeof(TEntity).FullName} 的默认构造函数。");
            }
            var properties = typeof(TEntity).GetProperties();
            foreach (var item in _entities)
            {
                var property = properties.First(x => x.Name == item.Key);
                property.SetValue(instance, item.Value);
            }
            return (TEntity)instance;
        }

        public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
        {
            return _entities.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        /// <summary>
        /// 隐式转换 重载
        /// </summary>
        /// <param name="instance"></param>
        /// <returns></returns>
        public static implicit operator Dictionary<string, object>(EntityDictionary<TEntity> instance)
        {
            return instance._entities;
        }

        /// <summary>
        /// 将EntityDictionary`
        /// <typeparamref name="TEntity"/>
        /// `转换为实例对象。
        /// </summary>
        /// <param name="instance"></param>
        /// <returns></returns>
        public static implicit operator TEntity(EntityDictionary<TEntity> instance)
        {
            return instance.Instance();
        }

        /// <summary>
        /// 隐式转换  重载
        /// </summary>
        /// <param name="dictionary"></param>
        /// <returns></returns>
        public static implicit operator EntityDictionary<TEntity>(Dictionary<string, object> dictionary)
        {
            EntityDictionary<TEntity> entity = new();
            var members = typeof(TEntity).GetTypeInfo().GetMembers().Where(member => member is FieldInfo or PropertyInfo);
            foreach (var item in dictionary)
            {
                if (members.Any(x => x.Name == item.Key))
                {
                    entity.Replace(item.Key, item.Value);
                }
            }
            return entity;
        }
    }
}
